#ifndef PLAYER_H
#define PLAYER_H

#include "fmod.h"
#include "core.h"
#include "../anime/engine.h"
#include "../anime/utils.h"

#include <QString>
#include <QLibrary>
#include <QMutex>
#include <QWaitCondition>

using namespace anime;

class PlayerListener
{
public:
    virtual void OnSegmentChange( int newSegment ) = 0;
};

class Player: private anime::Task,
              private AnimationObserver
{
public:
    static Player* GetInstance( anime::Engine* _e = 0 );
    static void DeleteInstance();

    // song control
    bool Open(const QString& songFilename);
    bool Close();
    bool Pause();
    bool Play();
    bool Stop();

    bool SetTime( int msecs );
    int GetTime( void );

    void SetVolume( float vol );

    void Synchronize( int downVolTime = 400, int upVolTime = 400, bool customSynchronization = false,
                      bool forceSynchronization = false );
    void EndSynchronize( void );

    bool IsPlaying( void );
    bool IsSynchronizing( void );

    void SetPlaybackMode( bool followSegments );

    int GoToNextSegment( void );
    int GoToPreviousSegment( void );

    void AddPlayerListener( PlayerListener* pl );
    void RemovePlayerListener( PlayerListener* pl );
    void ClearListeners( void );

    Song* song;
    int segmentPlaying; 
    bool normalPlayback;
    bool loopsTracking;

    // needed for the end callback
    int activeChannel;
    int vol;
    bool firstSynchronization;

private:
    anime::Engine* e;

    QList< PlayerListener* > listeners;

    static Player* instance;
    static float k;

    FSOUND_STREAM* activeStream;

    float tempo;
    int pitch;

    bool playing;
    bool firstPlay;

    class VolSetter: public PropertySetter< int >
    {
    public:
        VolSetter( Player* _owner ):owner(_owner){}

        virtual void operator()(const int& val)
        {
            if( owner->activeStream != 0 && owner->synchronizing )
            {
                FSOUND_SetVolume( owner->activeChannel, val );
            }
        }

        Player* owner;
    };

    class SleeperThread: public QThread
    {
    public:
        SleeperThread( Player* _owner );

        void run( void );
        void StopIt( void );
        void Sleep( );

        Player* owner;

        QMutex m;
        QWaitCondition c;
        bool end;
    };

    SleeperThread* sleeper;
    VolSetter* vs;
    SimplePropertyGetter<int>* vg;
    bool synchronizing;
    IntGraph animeGraph;
    Animation* volAnime;
    OneMinus_NI< float >* om_ni;

    int volId;
    int msecsStart;
    int volUpTime;
    bool customSync;
    float newTempo;
    float newPitch;
    int intNewPitch;
    bool syncDone;
    void SyncDone( void );
    bool delayedSynchronization;

    // AnimationObserver implementation
    virtual void OnPause(Animation* a);
    virtual void OnStop(Animation* a);
    virtual void OnEnd(Animation* a);
    virtual void OnPlay(Animation* a);

    Player( anime::Engine* _e );
    ~Player();

    bool LoadLibrary( void );
    float CalculatePitch( float t, int p );

    // anime::Task implementation
    void DoTask();
};

#endif // PLAYER_H
